package cn.iocoder.yudao.module.scrm.service.order;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils;
import cn.iocoder.yudao.framework.excel.core.strategy.DictTenantContext;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import cn.iocoder.yudao.module.scrm.controller.admin.business.vo.business.BusinessDetailVO;
import cn.iocoder.yudao.module.scrm.controller.admin.invoice.vo.InvoicePageReqVO;
import cn.iocoder.yudao.module.scrm.dal.dataobject.business.BusinessDO;
import cn.iocoder.yudao.module.scrm.dal.dataobject.clue.ClueDO;
import cn.iocoder.yudao.module.scrm.dal.dataobject.customer.CustomerDO;
import cn.iocoder.yudao.module.scrm.dal.dataobject.invoice.InvoiceDO;
import cn.iocoder.yudao.module.scrm.dal.dataobject.receivable.ReceivableDO;
import cn.iocoder.yudao.module.scrm.dal.dataobject.refund.RefundDO;
import cn.iocoder.yudao.module.scrm.dal.mysql.customer.CustomerMapper;
import cn.iocoder.yudao.module.scrm.dal.mysql.invoice.InvoiceMapper;
import cn.iocoder.yudao.module.scrm.dal.mysql.receivable.ReceivableMapper;
import cn.iocoder.yudao.module.scrm.dal.mysql.refund.RefundMapper;
import cn.iocoder.yudao.module.scrm.enums.common.CrmBizTypeEnum;
import cn.iocoder.yudao.module.scrm.enums.common.ScrmOrderTypeEnum;
import cn.iocoder.yudao.module.scrm.service.clue.ClueServiceImpl;
import cn.iocoder.yudao.module.scrm.util.CheckNoGeneratorUtil;
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.mzt.logapi.context.LogRecordContext;
import com.mzt.logapi.starter.annotation.LogRecord;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import cn.iocoder.yudao.module.scrm.controller.admin.order.vo.*;
import cn.iocoder.yudao.module.scrm.dal.dataobject.order.OrderDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;

import cn.iocoder.yudao.module.scrm.dal.mysql.order.OrderMapper;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertListByFlatMap;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
import static cn.iocoder.yudao.module.scrm.enums.DictTypeConstants.*;
import static cn.iocoder.yudao.module.scrm.enums.DictTypeConstants.SCRM_CLUE_STATE;
import static cn.iocoder.yudao.module.scrm.enums.ErrorCodeConstants.*;
import static cn.iocoder.yudao.module.scrm.enums.LogRecordConstants.*;
import static cn.iocoder.yudao.module.scrm.enums.common.ScrmOrderTypeEnum.*;

/**
 * 订单 Service 实现类
 *
 * @author admin
 */
@Service
@Validated
public class OrderServiceImpl implements OrderService {

    @Resource
    private OrderMapper orderMapper;

    @Resource
    private CheckNoGeneratorUtil checkNoGeneratorUtil;

    @Resource
    private CustomerMapper customerMapper;

    @Resource
    private AdminUserApi adminUserApi;

    @Resource
    private DeptApi deptApi;

    @Resource
    private ReceivableMapper receivableMapper;

    @Resource
    private RefundMapper refundMapper;

    @Resource
    private InvoiceMapper invoiceMapper;

    @Resource
    private PermissionApi permissionApi;


    @Override
    public List<OrderDO> getOrderList(Collection<Integer> ids) {
        if (CollUtil.isEmpty(ids)) {
            return Collections.emptyList();
        }
        return orderMapper.selectBatchIds(ids);
    }

    @Override
    public Integer createOrder(OrderSaveReqVO createReqVO,String tenantId) {
        // 插入
        OrderDO order = BeanUtils.toBean(createReqVO, OrderDO.class);
        // 设置系统编号
        order.setSystemNumber(checkNoGeneratorUtil.generateUniqueCheckNo(CrmBizTypeEnum.CRM_ORDER.getType()));
        //将微信id转换成id进行添加
        order.setOwnerUserId(String.valueOf(adminUserApi.getLeaderByWxIdNotCheckDataPermission(createReqVO.getOwnerUserId(),tenantId).getCheckedData().getId()));

        orderMapper.insert(order);
        // 返回
        return order.getId();
    }

    @Override
    public void updateOrder(OrderSaveReqVO updateReqVO,String tenantId) {
            // 校验存在-如果提交了流程抛错误不然进行修改
            validateOrderExists(updateReqVO.getId());
            // 1 旧的人员数据
            OrderDO orderDO = validateOrderExist(updateReqVO.getId());
            //旧的所属人员id
            String oldUserId = String.valueOf(adminUserApi.getUserNotCheckDataPermission(Long.valueOf(orderDO.getOwnerUserId())).getCheckedData().getId());

            //将微信id转换成id进行添加--修改的时候改变了归属人员才进行设置归属人员
            if (!Objects.equals(oldUserId, updateReqVO.getOwnerUserId())){
                updateReqVO.setOwnerUserId(String.valueOf(adminUserApi.getLeaderByWxIdNotCheckDataPermission(updateReqVO.getOwnerUserId(),tenantId).getCheckedData().getId()));
            }
            //新的所属人员id
            String newUserId = String.valueOf(adminUserApi.getUserNotCheckDataPermission(Long.valueOf(updateReqVO.getOwnerUserId())).getCheckedData().getId());
            //当传入的归属人与之前的不一样设置前归属人
            if (!newUserId.equals(oldUserId)){
                updateReqVO.setOldOwnerUserId(String.valueOf(oldUserId));
            }else{
                updateReqVO.setOwnerUserId(String.valueOf(newUserId));
            }
            // 更新
            OrderDO updateObj = BeanUtils.toBean(updateReqVO, OrderDO.class);
            orderMapper.updateById(updateObj);
    }

    @Override
    public void deleteOrder(Integer id) {
        // 校验存在
        validateOrderExists(id);
        OrderDO orderDO = orderMapper.selectById(id);
        //校验是否有子集
        validateOrderSubsetExists(id,orderDO.getSystemNumber());
        // 删除
        orderMapper.deleteById(id);
    }

    private void validateOrderSubsetExists(Integer orderId,String systemNumber) {
        List<ReceivableDO> receivableDOList = receivableMapper.selectList(ReceivableDO::getOrderId, orderId);
        List<RefundDO> refundDOList = refundMapper.selectList(RefundDO::getOrderId, orderId);
        List<InvoiceDO> invoiceDOList = invoiceMapper.selectList(InvoiceDO::getOrderId, orderId);
        if (receivableDOList != null && !receivableDOList.isEmpty()) { // 防御一下
            throw exception(ORDER_EXIST_RECEIVABLE,systemNumber);
        }
        if (refundDOList != null && !refundDOList.isEmpty()) { // 防御一下
            throw exception(ORDER_EXIST_REFUND,systemNumber);
        }
        if (invoiceDOList != null && !invoiceDOList.isEmpty()) { // 防御一下
            throw exception(ORDER_EXIST_INVOICE,systemNumber);
        }
    }

    private void validateOrderExists(Integer id) {
        OrderDO orderDO = orderMapper.selectById(id);
        if ( orderDO== null) {
            throw exception(ORDER_NOT_EXISTS);
        }else if ("1".equals(orderDO.getInstanceIfSubmit())){
            throw exception(ORDER_NOT_REPETITION_SUBMIT);
        }
    }

    private OrderDO validateOrderExist(Integer id) {
        OrderDO orderDO = orderMapper.selectById(id);
        if (orderDO == null) {
            throw exception(ORDER_NOT_EXISTS);
        }
        return orderDO;
    }

    @Override
    public OrderRespVO getOrder(Integer id,String tenantId) {
        OrderDO orderDO = orderMapper.selectById(id);


        OrderRespVO orderRespVO = BeanUtils.toBean(orderDO, OrderRespVO.class);

        /*if (orderDO.getFileUrl()!=null && !"".equals(orderDO.getFileUrl())){
            List<OrderFileListVo> fileList = JsonUtils.parseArray(orderDO.getFileUrl().toString(), OrderFileListVo.class);
            orderRespVO.setFileUrlVo(fileList);
        }

        if (orderDO.getPictureAttachment()!=null && !"".equals(orderDO.getPictureAttachment())){
            List<OrderFileListVo> fileList = JsonUtils.parseArray(orderDO.getPictureAttachment().toString(), OrderFileListVo.class);
            orderRespVO.setPictureAttachmentVo(fileList);
        }*/

        this.setUserAndDeptInfo(orderRespVO,tenantId,OWNER_USER.getType());
        this.setUserAndDeptInfo(orderRespVO,tenantId,OLD_OWNER_USER.getType());
        this.setUserAndDeptInfo(orderRespVO,tenantId,OUR_SIGNATORY.getType());
        this.setUserAndDeptInfo(orderRespVO,tenantId,CUSTOMER_NAME.getType());
        this.setUserAndDeptInfo(orderRespVO,tenantId,null);
        return orderRespVO;


    }

    /**
     * 根据类型设置前归属人|当前归属人的-姓名和部门名称 | 当前签约人姓名 | 客户名称
     * @param orderRespVO 设置后-返回的参数
     * @param tenantId 租户id
     * @param type 类型 1 当前归属人 2 前归属人 3 签约人 4 客户名称
     */
    private void setUserAndDeptInfo(OrderRespVO orderRespVO, String tenantId,String type) {
        if(OWNER_USER.isType(type)){
            //当前归属人员姓名和部门

            if (orderRespVO.getOwnerUserId()!=null && !orderRespVO.getOwnerUserId().isEmpty()){
                CommonResult<AdminUserRespDTO> ownerUser = adminUserApi.getUserNotCheckDataPermission(Long.valueOf(orderRespVO.getOwnerUserId()));
                AdminUserRespDTO ownerUserData = ownerUser.getData();
                if (ownerUserData!=null ){
                    orderRespVO.setOwnerUserIdName(ownerUserData.getNickname());
                    if (ownerUserData.getDeptId()!=null){
                        DeptRespDTO deptRespDTO = deptApi.getDeptNotCheckDataPermission(ownerUserData.getDeptId()).getCheckedData();
                        if (deptRespDTO!=null){
                            orderRespVO.setOwnerUserIdDept(deptRespDTO.getName());
                        }
                    }
                }
            }

        }else if (ScrmOrderTypeEnum.OLD_OWNER_USER.isType(type)){
            //前归属人员姓名和部门
            if (orderRespVO.getOldOwnerUserId()!=null && !orderRespVO.getOldOwnerUserId().isEmpty()){
                CommonResult<AdminUserRespDTO> oldOwnerUser = adminUserApi.getUserNotCheckDataPermission(Long.valueOf(orderRespVO.getOldOwnerUserId()));
                AdminUserRespDTO ownerUserData = oldOwnerUser.getData();
                if (ownerUserData!=null ){
                    orderRespVO.setOldOwnerUserIdName(ownerUserData.getNickname());
                    if (ownerUserData.getDeptId()!=null){
                        DeptRespDTO deptRespDTO = deptApi.getDeptNotCheckDataPermission(ownerUserData.getDeptId()).getCheckedData();
                        if (deptRespDTO!=null){
                            orderRespVO.setOldOwnerUserIdDept(deptRespDTO.getName());
                        }
                    }
                }
            }

        }else if (OUR_SIGNATORY.isType(type)){

            //签约人员名称
            Optional.ofNullable(orderRespVO.getOurSignatory())
                    .ifPresent(customerId -> {
                        CommonResult<AdminUserRespDTO> userAdmins = adminUserApi.getLeaderByWxIdNotCheckDataPermission(orderRespVO.getOurSignatory(), tenantId);
                        AdminUserRespDTO data = userAdmins.getData();
                        Optional.ofNullable(data)
                                .ifPresent(ourSignatoryName -> orderRespVO.setOurSignatoryName(data.getNickname()));
                    });

        }else if (CUSTOMER_NAME.isType(type)){
            //客户名称
            Optional.ofNullable(orderRespVO.getCustomerId())
                    .ifPresent(customerId -> {
                        CustomerDO customerDO = customerMapper.selectById(customerId);
                        Optional.ofNullable(customerDO)
                                .ifPresent(customer -> orderRespVO.setCustomerName(customer.getName()));
                    });

        } else {
            //创建人员姓名
            Optional.ofNullable(orderRespVO.getCreator())
                    .ifPresent(id -> {
                        CommonResult<AdminUserRespDTO> creatorDTO = adminUserApi.getUserNotCheckDataPermission(Long.valueOf(id));
                        AdminUserRespDTO creatorData = creatorDTO.getData();
                        Optional.ofNullable(creatorData)
                                .ifPresent(name -> orderRespVO.setCreatorName(creatorData.getNickname()));
                    });
        }


    }

    @Override
    public PageResult<OrderDetailPageVO> getOrderPage(OrderPageReqVO pageReqVO) {

        PageResult<OrderDO> list = orderMapper.selectPage(pageReqVO);
        PageResult<OrderDetailPageVO> detailVoPage = BeanUtils.toBean(list, OrderDetailPageVO.class);

        //根据值不为空进行缓存中的字典查询
        List<OrderDetailPageVO> detailVoList = detailVoPage.getList();
        //兼容对于同一个字段不同租户使用不同得字典的情况   -
        Long tenantId = TenantContextHolder.getTenantId();
        //使用不同租户对应不同策略
        DictTenantContext tenantContext = new DictTenantContext(Math.toIntExact(tenantId));

        // 1.1 获取创建人、负责人列表
        Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMapNotCheckDataPermission(convertListByFlatMap(detailVoList, contact -> Stream.of(NumberUtils.parseLong(String.valueOf(contact.getCreator())), contact.getOwnerUserId())));
        Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMapNotCheckDataPermission(convertSet(userMap.values(), AdminUserRespDTO::getDeptId));

        detailVoList.forEach(orderDO -> {
            Optional<String> paymentMethodOptional = Optional.ofNullable(orderDO.getPaymentMethod());
            paymentMethodOptional.ifPresent(clientSource -> orderDO.setPaymentMethod(tenantContext.getDictDataLabel(SCRM_PAYMENT_METHOD, clientSource)));

            Optional<String> orderTypeOptional = Optional.ofNullable(orderDO.getOrderType());
            orderTypeOptional.ifPresent(infoSource -> orderDO.setOrderType(tenantContext.getDictDataLabel(SCRM_ORDER_TYPE, infoSource)));

            //不为空的时候根据客户id设置客户名称
            Optional.ofNullable(orderDO.getCustomerId())
                    .map(customerMapper::selectById)
                    .map(CustomerDO::getName)
                    .ifPresent(orderDO::setCustomerName);

            //设置、负责人姓名、部门
            MapUtils.findAndThen(userMap, orderDO.getOwnerUserId(), user -> {
                orderDO.setOwnerUserIdName(user.getNickname());
                MapUtils.findAndThen(deptMap, user.getDeptId(), dept -> orderDO.setOwnerUserIdDept(dept.getName()));
            });

            //根据订单id  去获取已回款金额 | 已开票金额  一对多 //TODO不计算已驳回的
            // 创建一个 LambdaQueryWrapper 对象
            LambdaQueryWrapper<InvoiceDO> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(InvoiceDO::getOrderId, orderDO.getId()) // 设置订单 ID 条件
                    .ne(InvoiceDO::getAuditStatus, 3); // 设置审核状态不为已驳回的数据
            LambdaQueryWrapper<ReceivableDO> queryWrapperReceivable = new LambdaQueryWrapper<>();
            queryWrapperReceivable.eq(ReceivableDO::getOrderId, orderDO.getId()) // 设置订单 ID 条件
                    .ne(ReceivableDO::getAuditStatus, 3); // 设置审核状态不为已驳回的数据


            // 执行查询
            List<InvoiceDO> invoiceDOList = invoiceMapper.selectList(queryWrapper);
            List<ReceivableDO> receivableDOList = receivableMapper.selectList(queryWrapperReceivable);

            //设置开票金额
            BigDecimal invoiceSumMoney = invoiceDOList.stream()
                    .map(InvoiceDO::getPrice)
                    .filter(Objects::nonNull)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            orderDO.setInvoiceMoney(invoiceSumMoney);

            //设置回款金额
            BigDecimal receivableMoney = receivableDOList.stream()
                    .map(ReceivableDO::getPrice)
                    .filter(Objects::nonNull)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            orderDO.setReceivableMoney(receivableMoney);

            //我方签约人
            Optional.ofNullable(orderDO.getOurSignatory())
                    .ifPresent(customerId -> {
                        CommonResult<AdminUserRespDTO> userAdmins = adminUserApi.getLeaderByWxIdNotCheckDataPermission(orderDO.getOurSignatory(), String.valueOf(tenantId));
                        AdminUserRespDTO data = userAdmins.getData();
                        Optional.ofNullable(data)
                                .ifPresent(ourSignatoryName -> orderDO.setOurSignatoryName(data.getNickname()));
                    });

        });
        return detailVoPage;
    }

    @Override
    public Boolean transferOrder(OrderTransfersVo reqVO, Long loginUserId,String tenantId) {
        AdminUserRespDTO newData = adminUserApi.getLeaderByWxIdNotCheckDataPermission(reqVO.getNewOwnerUserId(), tenantId).getData();
        Long newUserId =newData.getId();
        String newNickname = newData.getNickname();
        for (Integer id : reqVO.getIds()) {
            // 1. 校验订单是否存在
            OrderDO orderDO = validateOrderExist(id);
            String orderName = orderDO.getTitle();
            String oldOrderRemark = orderDO.getRemark();
            //获取旧的负责人数据
            AdminUserRespDTO oldData = adminUserApi.getUserNotCheckDataPermission(Long.valueOf(orderDO.getOwnerUserId())).getData();
            String oldNickname="空";
            if (oldData!=null){
                  oldNickname = oldData.getNickname();
            }

            // 2. 判断 订单当前归属人与要设置的归属人是否一样
            if (!orderDO.getOwnerUserId().equals(newUserId.toString())) {
                String newOrderRemark = reqVO.getRemark();
                // 2.1 设置新的负责人-和前归属人-
            orderMapper.updateById(new OrderDO()
                    .setId(id)
                    .setOwnerUserId(String.valueOf(newUserId))
                    .setOldOwnerUserId(orderDO.getOwnerUserId())
                    .setRemark(newOrderRemark));
                getSelf().transferOrderLog(id,orderName,oldNickname,newNickname,newOrderRemark,oldOrderRemark);
            }





            /*//转移相关的 2 客户| 7 合同 | 10 回款-暂时不要
            Set<Integer> associatedDataType = reqVO.getAssociatedDataType();
            for (Integer type : associatedDataType) {
                if(ObjUtil.equal(CrmBizTypeEnum.CRM_CUSTOMER.getType(), type)) {

                } else if(ObjUtil.equal(CrmBizTypeEnum.CRM_RECEIVABLE.getType(), type)) {

                }else if(ObjUtil.equal(CrmBizTypeEnum.CRM_INVOICE.getType(), type)) {

                }
            }*/

        }
        return true;
    }


    //转移线索日志操作
    @LogRecord(type = SCRM_ORDER_TYPE_LOG, subType = SCRM_ORDER_UPDATE_SUB_TYPE, bizNo = "{{#orderId}}",
            success = SCRM_ORDER_TRANSFER_SUCCESS)
    public void transferOrderLog(Integer orderId, String orderName, String oldOrderPerson, String newOrderPerson, String newRemark, String oldRemark) {
        // 设置日志记录上下文变量
        //LogRecordContext.putVariable("orderId", orderId);
        LogRecordContext.putVariable("orderName",orderName);
        LogRecordContext.putVariable("oldOrderPerson", oldOrderPerson);
        LogRecordContext.putVariable("newOrderPerson", newOrderPerson);
        LogRecordContext.putVariable("oldRemark", oldRemark);
        LogRecordContext.putVariable("newRemark", newRemark);

    }

    /**
     * 获得自身的代理对象，解决日志记录在 AOP操作下对于this.方法生效问题
     * @return 自己
     */
    private OrderServiceImpl getSelf() {
        return SpringUtil.getBean(getClass());
    }

}